package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"iot-base/common/cache"
	"iot-base/common/common"
	"iot-base/common/dbconn"
	"iot-base/common/logger"
	"net/http"
	_ "net/http/pprof"

	//"iot-base/common/ctrltype"

	"iot-base/devc/common/loader"
	"net"
	"sync"
	"time"
)

//用于连接
var conn net.Conn

var boxistrue map[string]string //用于存储设备id =》 设备参数uid
var boxmap map[string]string    //用于存储设备uid =》 存储设备id
//var readbuff []byte
var Mux sync.Mutex

func getTimeout() int {
	count := loader.GetDevCount()
	if count < 10 {
		return 2
	} else if count < 100 {
		return 10
	} else if count < 500 {
		return 20
	} else {
		return 30
	}
}
func removeAll() {
	removeDev("ALL")
}
func removeDev(uid string) {
	wr, err := json.Marshal(RemoveDev{"RemoveDev", []DevMsg{DevMsg{uid}}})
	if err != nil {
		fmt.Println("marshal err:", err)
	}
	WriteDt(wr, conn)
	readdt := ReadDt(conn)
	var res ResRemoveDev
	//var tmp map[string]interface{}
	err = json.Unmarshal(readdt, &res)
	if err != nil {
		fmt.Println("unmarshal err make protocol:", string(readdt), err)
	}
	fmt.Println("resdev:", res)
}
func initGin() {

	// http.HandleFunc("/", pprof.Index)
	// http.HandleFunc("/cmdline", pprof.Cmdline)
	// http.HandleFunc("/profile", pprof.Profile)
	// //http.HandleFunc("/symbol", pprof.Symbol)
	// http.HandleFunc("/symbol", pprof.Symbol)
	// http.HandleFunc("/trace", pprof.Trace)
	// http.HandleFunc("/allocs", pprof.Handler("allocs").ServeHTTP)
	// http.HandleFunc("/block", pprof.Handler("block").ServeHTTP)
	// http.HandleFunc("/goroutine", pprof.Handler("goroutine").ServeHTTP)
	// http.HandleFunc("/heap", pprof.Handler("heap").ServeHTTP)
	// http.HandleFunc("/mutex", pprof.Handler("mutex").ServeHTTP)
	// http.HandleFunc("/threadcreate", pprof.Handler("threadcreate").ServeHTTP)
	go http.ListenAndServe(":6060", nil)
}

type thingInfo struct {
	id string
	ip string
}

var mapCache = make(map[string]thingInfo)

func main() {

	defer func() {
		if err := recover(); err != nil {
			logger.SLog.Fatal("panic-----------", err)
			common.PrintStack()

		}
		fmt.Println("c")
	}()
	initGin()
	boxistrue = make(map[string]string)
	boxmap = make(map[string]string)
	var infos []map[string]interface{}
	dbconn.DBConnection.Raw(`select things.uid as tid,
	tp1.param_value as uid,
	tp2.param_value as ip
	from things left join thing_params as tp1 on things.uid = tp1.thing_id and tp1.param_id = 'UID'
	left join thing_params as tp2 on things.uid = tp2.thing_id and tp2.param_id = 'IP'
	where things.model_id='m_smartBoxForPolice'`).Scan(&infos)
	if len(infos) > 0 {
		Mux.Lock()
		for _, info := range infos {
			tid := info["tid"]
			if tid != nil {
				uid := info["uid"]
				if uid != nil {
					stid := tid.(string)
					suid := uid.(string)
					boxistrue[stid] = suid
					boxmap[suid] = stid

				}
			}

		}
		Mux.Unlock()
	}

	if conn == nil {
		var err error
		conn, err = net.DialTimeout("tcp", "127.0.0.1:37125", 3*time.Second)
		if err != nil {
			fmt.Println("conn server err:", err)
		}
		fmt.Println("conn success:", conn)
	}
	// var infos []map[string]interface{}
	// var infoDevs []map[string]interface{}
	// dbconn.DBConnection.Raw(`select tp1.uid as tid,tp2.uid as uid,tp2.ip as ip from things t
	//  left join thing_params tp1 on tp1.thing_id = t.uid and tp1.param_id='UID'
	//  left join thing_params tp2 on tp2.thing_id = t.uid and tp2.param_id='IP'
	//  where t.model_id='m_smartBoxForPolice'`)
	//  .Find(&infos)
	//  cmd := "{\"REQ\":\"DevUidList\"}\r\n"
	//  WriteDt([]byte(cmd), conn)
	//  rt, _ := ReadDtEx(conn)
	//  json.Unmarshal([]byte(rt),&infoDevs)
	//  var devlist []string
	//  if len(infos) > 0 && len(infoDevs){
	// 	 devs := infoDevs["Ok"]
	// 	 if devs != nil{
	// 		 devlist,_ = devs.([]string)

	// 	 }
	// 	 for _,values := range infos{
	// 		 tid := values["tid"]
	// 		 uid := values["uid"]
	// 		 ip := values["ip"]
	// 		 stid,_ := tid.(string)
	// 		 suid,_ := uid.(string)
	// 		 sip,_ := ip.(string)

	// 		 mapCache[suid] = thingInfo{
	// 			 id : stid,
	// 			 ip : sip,
	// 		 }
	// 	}
	// 	for _,uid := range devlist{
	// 		info,ok := mapCache[uid]
	// 		if !ok{
	// 			removeDev(uid)
	// 		}
	// 	}
	// 	saveFile()
	// }

	//}

	//removeAll()
	loader.Init("box")
	timeout := getTimeout()
	loader.SetParam(false, "box", timeout, eachDev)
	loader.TellDMNotToCheckOnline()
	loader.SetThingChangedCallback(func(ctype string, id string) {

		if ctype == "delete" && id != "" {
			Mux.Lock()
			uid := boxistrue[id]
			if uid != "" {
				delete(boxmap, uid)
				delete(boxistrue, id)
				//ctype = "delete"
			}
			Mux.Unlock()
			fmt.Println("***************remove from media soft****************", uid)
			removeDev(uid)
			saveFile()

		} else {
			pInfo, _ := cache.GetThing(id)
			var uid, ip string
			if pInfo != nil {
				uid = pInfo.Params["UID"]
				ip = pInfo.Params["IP"]
			}

			if uid != "" && ip != "" {
				AddDevf(uid, ip)
				saveFile()

			}
			Mux.Lock()
			uidOld := boxistrue[id]
			if uid != uidOld {
				delete(boxmap, uidOld)
				//delete(boxistrue, uidOld)
				boxistrue[id] = uidOld
				//ctype = "delete"
			}
			Mux.Unlock()
			go getData(uid, id, pInfo)
		}
		chanForID <- id

	})

	RegistServe()

	go ReportAlarm()

	wg := sync.WaitGroup{}
	wg.Add(1)
	wg.Wait()
	fmt.Println("----------exit normally-----------")
}

var mapOnline sync.Map

var isCallReportAlarm = false

func saveids(ids []string) {
	devAdds := make([]DevAdd, 0, len(ids))

	for _, id := range ids {
		pThing, _ := cache.GetThing(id)
		if pThing != nil {
			uid := pThing.Params["UID"]
			ip := pThing.Params["IP"]
			Mux.Lock()
			boxistrue[id] = uid
			boxmap[uid] = id
			Mux.Unlock()
			devAdds = append(devAdds, DevAdd{IP: ip, UID: uid, Adr: "12"})

		}
	}
	AddDevfEx(conn, devAdds)
	//saveFile()
}

//设备增加的回调
func eachDev(id string, thing *cache.ThingInfo, dev interface{}, num int64) (interface{}, error) {

	if conn == nil {
		var err error
		conn, err = net.DialTimeout("tcp", "127.0.0.1:37125", 3*time.Second)
		if conn == nil || err != nil {
			logger.SLog.Warn("box cannot connect", err)
			return nil, err
		}
	}
	// if num == 1 {
	// 	cmd := "{\"REQ\":\"DevUidList\"}\r\n"
	// 	WriteDt([]byte(cmd), conn)
	// 	rt, err := ReadDtEx(conn)
	// 	if err == io.EOF {
	// 		conn = net.DialTimeout("tcp", "127.0.0.1:37125", 3*time.Second)
	// 	}

	// }

	// if num%20 == 0 && num != 0 {
	// 	go ForceSave()
	// }

	//var uid = ""
	var ip = ""
	var needAdd = false
	Mux.Lock()
	uid, _ := boxistrue[id]
	if uid == "" {
		uid = thing.Params["UID"]
		boxmap[uid] = id
		boxistrue[id] = uid
		needAdd = true
	}
	Mux.Unlock()

	if ip == "" {
		ip = thing.Params["IP"]
		if ip == "" {
			logger.SLog.Error("ip not found------", ip, id)
			return nil, errors.New("该设备没有配置ip")
		}
	}
	if needAdd {

		AddDevf(uid, ip)
		saveFile()
	}

	//beginCheck(id, ip, &mapOnline)

	if num == 0 {
		// if !isOnline(id, &mapOnline) {
		// 	return nil, nil
		// }
		getData(uid, id, thing)
	}

	//beginCheck(id, ip, &mapOnline)

	//else {

	// 	//fmt.Println("***************error*************get data ", err, devMsg, uid)
	// }
	//func RawData(tid string, pid string, subid string, index int, value interface{},
	//	reportTime int64, pickTIme int64)
	return nil, nil

}

func AddDevf(uid string, ip string) {
	if conn == nil || ip == "" {
		return
	}
	//fmt.Println("---------id or---ip changed---------------", uid, ip)
	adddev, err := json.Marshal(AddDev{"AddDev", []DevAdd{{uid, ip, "12"}}})
	//fmt.Println(string(adddev))
	if err != nil {
		fmt.Println("marshal err:", err)
	}
	n, err := conn.Write(adddev)
	conn.Write([]byte("\r\n"))
	if n == 0 || err != nil {
		fmt.Println("write err,n:", err, n)
		conn = nil
		return
	}
	ReadDt(conn)
	if n == 0 || err != nil {
		fmt.Println("read err:", err)
		conn = nil
		return
	}
	/*var res ResAddDev
	json.Unmarshal(readbuff, &res)
	*/
	//fmt.Println("ResAddDev:", res)
}

func GetDevMsg(uid string, connection net.Conn) (*ResDevMsg, error) {

	if connection == nil {
		return nil, errors.New("connetion lost")
	}
	getmsg, err := json.Marshal(GetBaseMsg{"GetBaseMsg", []DevMsg{DevMsg{uid}}}) //, []ResDev{DevMsg{uid}}})
	//fmt.Println(string(getmsg))
	if err != nil {
		fmt.Println("marshal err:", err)
		return nil, err
	}
	n, err := connection.Write(getmsg)
	connection.Write([]byte(`\r\n`))
	if n == 0 || err != nil {
		fmt.Println("write err,n:", err, n)
		//conn = nil
		return nil, err
	}
	buffer := ReadDt(connection)
	if len(buffer) == 0 {
		return nil, nil
	}
	var resmsg ResDevMsg
	err = json.Unmarshal(buffer, &resmsg)
	//fmt.Println("ResDevMsg", string(readbuff[:n]))
	if err != nil {
		fmt.Println("unmarshal err22:", err, string(buffer))
		return nil, err
	}
	return &resmsg, nil
}

func AddDevfEx(conn net.Conn, devs []DevAdd) {
	if conn == nil {
		return
	}
	//fmt.Println("---------id or---ip changed---------------", uid, ip)
	adddev, err := json.Marshal(AddDev{"AddDev", devs})
	//fmt.Println(string(adddev))
	if err != nil {
		fmt.Println("marshal err:", err)
	}
	n, err := conn.Write(adddev)
	if n == 0 || err != nil {
		fmt.Println("write err,n:", err, n)
		conn = nil
		return
	}
	ReadDt(conn)
	if n == 0 || err != nil {
		fmt.Println("read err:", err)
		conn = nil

	}
	saveFile()
	/*var res ResAddDev
	json.Unmarshal(readbuff, &res)
	*/
	//fmt.Println("ResAddDev:", res)
}
